﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
public enum ColorTargetType
{
    Hair,
    Skin,
    EyeWhite,
    Eye,
    EyeBrow,
    EyeLash,
    EyeFold,
    EyeHl,
    EyeHl2,
    EyePupil,
}
public class SliderMgr : MonoBehaviour
{
    public ButtonSlider hairEndSelector;
    public ButtonSlider hairSelector;
    public LabelSlider hairSegmentSlider;
    public int origin;
    public int max;
    public int min;

    public ColorTargetType colorTargetType;
    public ButtonSlider colorTargetSelector;
    public Vector3 colorTargetMOM;

    public Color rangeOrigin;
    public Color rimOrigin;
    public Color matCapOrigin;
    public Color lightOrigin;
    public Color darkOrigin;
    public Color dark2Origin;

    public ColorPickerSlider rangeHlSlider;
    public ColorPickerSlider rimSlider;
    public ColorPickerSlider matCapSlider;
    public ColorPickerSlider lightSlider;
    public ColorPickerSlider darkSlider;
    public ColorPickerSlider dark2Slider;
    public LabelSlider rangeHlPowerSlider;
    public LabelSlider rimPowerSlider;
    public LabelSlider darkStepSlider;
    public LabelSlider darkFeatherSlider;
    public LabelSlider dark2StepSlider;
    public LabelSlider dark2FeatherSlider;
    public Vector3 rangeHlPowerMOM;
    public Vector3 rimPowerMOM;
    public Vector3 darkStepMOM; //x = Min, y = Origin, z = Max
    public Vector3 darkFeatherMOM;
    public Vector3 dark2StepMOM;
    public Vector3 dark2FeatherMOM;

    public LabelSlider matCapTileXSlider;
    public LabelSlider matCapTileYSlider;
    public Vector3 matCapTileXMOM;
    public Vector3 matCapTileYMOM;
    public string matCapTexName = "_NormalMapForMatCap";

    public LabelSlider matCapOffsetXSlider;
    public LabelSlider matCapOffsetYSlider;
    public Vector3 matCapOffsetXMOM;
    public Vector3 matCapOffsetYMOM;

    public HairUnitEmitter emitter;
    public HairUnitScaler scaler;
    public static bool mirrorControl;
    public Toggle mirrorControlToggle;
    public string rangeHlName;
    public string rangeHlPowerName;
    public string rimName;
    public string rimPowerName;
    public string matCapName;
    public string lightName;
    public string darkName;
    public string dark2Name;
    public string darkStepName;
    public string darkFeatherName;
    public string dark2StepName;
    public string dark2FeatherName;
    public bool ignoreValueChanges;
    public bool editable = true;
    public GameObject[] blocks;
    public SkinnedMeshRenderer smrSkin;
    public SkinnedMeshRenderer smrEyeWhite;
    public SkinnedMeshRenderer smrEye;
    public SkinnedMeshRenderer smrEyeBrow;
    public SkinnedMeshRenderer smrEyeLash;
    public SkinnedMeshRenderer smrEyeFold;
    public SkinnedMeshRenderer smrEyeHl;
    public SkinnedMeshRenderer smrEyeHl2;
    public SkinnedMeshRenderer smrEyePupil;

    public Button faceCodeOpenButton;
    public Button faceCodeSaveButton;

    public Toggle manualSectionPosToggle;
    public bool manualSectionPosOn;
    public ManualGizmos manualGizmos;

    public Toggle manualKeepChildPosToggle;
    public bool manualKeepChildPosOn;
    public Toggle manualKeepParentRotToggle;
    public bool manualKeepLookAtRotOn;
    public LabelSlider manualDragSensitivitySlider;
    public Vector3 manualDragSensitivityMOM;

    public Toggle eyeBrowBoneToggle;
    public Toggle eyeFoldToggle;
    public Toggle eyeLashToggle;
    public Toggle eyeHlToggle;
    public Toggle eyeHl2Toggle;
    public Shader shaderSelected;
    public Shader shaderUnSelected;

    public float proportionalEditRangeUIAccurracy;
    public Color proportionalEditRangeColor;
    public float proportionalEditRangeValue;
    public LabelSlider proportionalEditRangeSlider;
    public Vector3 proportionalEditRangeMOM;
    public Toggle proportionalEditToggle;
    public bool proportionalEditOn;
    public float proportionalEditPostRenderZ;

    public Toggle outlineDisplayToggle;
    public RTOverlay outlineDisplay;

    public Toggle paintModeToggle;
    public FacePainter painter;

    public LabelSlider mouseDragSensitivitySlider;
    public Vector3 mouseDragSensitivityMOM;
    public Toggle windToggle;
    public string rimToggleName = "_RimLight";
    public Toggle rimToggle;

    public LabelSlider lightDirHorizonSlider;
    public Vector3 lightDirHorizonMOM;
    public LabelSlider lightDirVerticalSlider;
    public Vector3 lightDirVerticalMOM;
    public Toggle LightDirAutoTurnToggle;
    public LabelSlider LightDirAutoTurnSpeedSlider;
    public Vector3 LightDirAutoTurnSpeedMOM;
    float LightAutoTurnTimer;
    bool LightDirAutoTurnOn;

    public Encoding encoding = Encoding.UTF8;
    public string portraitHead = "portrait:{";
    public string hairHead = "hair:{";
    public string faceHead = "face:{";
    public char hairUnitSplit = '_';
    private FaceRigControl face;
    public Toggle mouseSelectModeOptionOne;
    public Toggle mouseSelectModeOptionTwo;

    public LabelSlider hairStencilOutAplhaSlider;
    public Vector3 hairStencilOutAplhaMOM;
    public string stencilOutAlphaName = "_StencilOutAlpha";

    public string colorsHead = "Colors:{";
    public string generalEnd = "}";
    public string texHead = "Tex={";
    public string texEnd = "}";
    public string mirrorHead = "Mirrors:{";
    public string settingsHead = "Settings:{";
    public bool busy = false;

    void OnHairStencilOutAplhaChanged(float v)
    {
        foreach (var unit in emitter.hairUnits)
        {
            unit.smr.sharedMaterial.SetFloat(stencilOutAlphaName, v);
        }
        emitter.unitPrefab.GetComponentInChildren<SkinnedMeshRenderer>(true).
            sharedMaterial.SetFloat(stencilOutAlphaName, v);
    }
    void OnLightDirAutoTurnToggleChanged(bool v)
    {
        LightAutoTurnTimer = 0f;
        if (!v)
        {
            OnLightDirHorizonChanged(lightDirHorizonSlider.value);
        }
        LightDirAutoTurnOn = v;
    }
    void OnLightDirHorizonChanged(float v)
    {
        var light = FindObjectOfType<Light>().transform;
        light.parent.SetLocalEulerY(v - light.localEulerAngles.y);
    }
    void OnLightDirVerticalChange(float v)
    {
        var light = FindObjectOfType<Light>().transform;
        light.parent.SetLocalEulerZ(360 - v);
    }
    void OnRimToggleChange(bool v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var on = rimToggle.isOn;
        SetFloat(rimToggleName, on ? 1 : 0);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.rimOn = on;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.rimOn = on;
            }
        }
    }
    void OnManualDragSensitivity(float v)
    {
        manualGizmos.axis.dragSensitivity = v;
    }
    void OnMouseDragSensitivity(float v)
    {
        FindObjectOfType<UnityChan.CameraController>().dragSensitivity = v;
    }
    void OnOutlineDisplayToggle(bool v)
    {
        outlineDisplay.enabled = v;
    }
    void OnProportionalEditToggle(bool v)
    {
        proportionalEditOn = v;
    }
    private void OnPostRenderCallBack()
    {
        var t = manualGizmos.axis.controlObj;
        if (t != null && proportionalEditOn)
        {
            GLHelper.DrawCircle(
                Camera.main.WorldToScreenPoint(t.position).SetZ(proportionalEditPostRenderZ),
                proportionalEditRangeValue,
                proportionalEditRangeColor,
                proportionalEditRangeUIAccurracy);
        }
    }
    void OnProportionalEditRangeChange(float v)
    {
        proportionalEditRangeValue = v;
    }
    private void OnEyeHl2Toggle(bool v)
    {
        smrEyeHl2.enabled = v;
    }
    private void OnEyeHlToggle(bool v)
    {
        smrEyeHl.enabled = v;
    }
    void OnEyeBrowBoneToggle(bool v)
    {
        smrEyeBrow.enabled = v;
    }
    void OnEyeFoldToggle(bool v)
    {
        smrEyeFold.enabled = v;
    }
    void OnEyeLashToggle(bool v)
    {
        smrEyeLash.enabled = v;
    }
    string TexPath(string p)// checkpath & add head if exist
    {
        string str = texHead;
        if (File.Exists(p))
        {
            p = p.Substring(p.LastIndexOf('/') + 1);
            str += p;
        }
        return str + texEnd;
    }
    string ExtractTexPath(ref string str)
    {
        return ExtractPath(ref str, texHead, texEnd);
    }
    string ExtractPath(ref string str, string texHead)
    {
        return ExtractPath(ref str, texHead, generalEnd);
    }
    string ExtractPath(ref string str, string head, string end)
    {
        string m = "";
        var index = str.IndexOf(head);
        if (index > -1)
        {
            var r = str.Substring(index + head.Length);
            str = str.Substring(0, index);
            var ind = r.IndexOf(end);
            if (ind >= 0)
            {
                m = r.Substring(0, ind);
                if (ind + 1 < r.Length)
                {
                    var r2 = r.Substring(ind + 1);
                    str += r2;
                    return m;
                }
            }
            else str += r;
        }
        return m;
    }
    void OnOpenFaceCode()
    {
        try
        {
            if (busy) return;
            busy = true;
            if (!File.Exists(painter.portraitFilePath)) { busy = false; return; }
            string str = File.ReadAllText(painter.portraitFilePath, encoding);
            painter.SetDropByText(painter.faceTexDrop, ExtractTexPath(ref str));
            painter.SetDropByText(painter.hairTexDrop, ExtractTexPath(ref str));
            painter.SetDropByText(painter.matCapTexDrop, ExtractTexPath(ref str));
            var units = ExtractPath(ref str, hairHead);
            if (units.Length > 0) // 如果包含头发信息
            {
                var uInfos = units.Split(hairUnitSplit);
                if (uInfos.Length > 0) emitter.Emit(uInfos.Length);
                for (int i = 0; i < emitter.hairUnits.Count; i++)
                {
                    var u = emitter.hairUnits[i];
                    u.ReadValuesFromFaceCode(uInfos[i]);
                    var poss = new List<Vector3>(u.sectionPosition);
                    var rots = new List<Quaternion>(u.sectionRotation);
                    ApplyUnitColorToMaterial(u);
                    ApplyUnitValues(u);
                    u.SetSectionTrans(poss.ToArray(), rots.ToArray());
                }
            }
            else emitter.ClearUnits();
            face.ReadCode(ExtractPath(ref str, faceHead));
            ReadTargetMatColorCode(ExtractPath(ref str, colorsHead));
            ReadUnitsMirrorConnect(ExtractPath(ref str, mirrorHead));
            ReadEnvironmentCode(ExtractPath(ref str, settingsHead));
            painter.OpenTexture();
            painter.OpenHairTexture();
            busy = false;
        }
        catch { busy = false; throw; }
    }
    void OnSaveFaceCode()
    {
        try
        {
            if (!File.Exists(painter.portraitFilePath)) return;
            string str = "";
            str += TexPath(painter.faceFilePath);
            str += TexPath(painter.hairFilePath);
            str += TexPath(painter.matCapFilePath);
            str += faceHead + face.GenerateCode() + generalEnd;
            str += GenerateTargetsColorCode() + generalEnd;
            str += hairHead;
            if (emitter.hairUnits.Count > 0)
            {
                for (int i = 0; i < emitter.hairUnits.Count; i++)
                {
                    str += emitter.hairUnits[i].GenerateReadableFaceCode() + hairUnitSplit;
                }
                str = str.Substring(0, str.Length - 1);
            }
            str += generalEnd;
            str += GenerateUnitsMirrorConnect() + generalEnd;
            str += GenerateEnvironmentCode() + generalEnd;
            File.WriteAllText(painter.portraitFilePath, str, encoding);
        }
        catch { throw; }
    }
    internal void ResetSettings()
    {
        lightDirHorizonSlider.value = lightDirHorizonMOM.y;
        lightDirVerticalSlider.value = lightDirVerticalMOM.y;
        hairStencilOutAplhaSlider.value = hairStencilOutAplhaMOM.y;
    }
    string GenerateEnvironmentCode()
    {
        string str = settingsHead;
        str += CodeGenerator.Float3_2ToString6(lightDirHorizonSlider.value) + '_';
        str += CodeGenerator.Float3_2ToString6(lightDirVerticalSlider.value) + '_';
        str += CodeGenerator.Float1_3ToString5(hairStencilOutAplhaSlider.value);
        return str;
    }
    void ReadEnvironmentCode(string v)
    {
        if (v.Length == 0) return;
        var data = v.Split('_');
        if (data.Length != 3) return;
        lightDirHorizonSlider.value = CodeGenerator.String6ToFloat3_2(data[0]);
        lightDirVerticalSlider.value = CodeGenerator.String6ToFloat3_2(data[1]);
        hairStencilOutAplhaSlider.value = CodeGenerator.String5ToFloat1_3(data[2]);
    }
    string GenerateUnitsMirrorConnect()
    {
        var str = mirrorHead;
        for (int i = 0; i < emitter.hairUnits.Count; i++)
        {
            string mirrorStr = emitter.hairUnits.IndexOf(emitter.hairUnits[i].mirror).ToString("000");
            string s = i.ToString("000") + '=' + mirrorStr;
            str += s + '_';
        }
        if (emitter.hairUnits.Count > 0) str = str.Substring(0, str.Length - 1);
        return str;
    }
    void ReadUnitsMirrorConnect(string v)
    {
        if (v.Length < 1) return;
        var data = v.Split('_');
        for (int i = 0; i < data.Length; i++)
        {
            string[] s = data[i].Split('=');
            int u = int.Parse(s[0]);
            int m = int.Parse(s[1]);
            emitter.hairUnits[u].mirror = m == -1 ? null : emitter.hairUnits[m];
        }
    }
    Material GetTargetMaterial(ColorTargetType type)
    {
        Material mat;
        switch (type)
        {
            case ColorTargetType.Skin:
                mat = smrSkin.sharedMaterial;
                break;
            case ColorTargetType.EyeWhite:
                mat = smrEyeWhite.sharedMaterials[2];
                break;
            case ColorTargetType.Eye:
                mat = smrEye.sharedMaterial;
                break;
            case ColorTargetType.EyeBrow:
                mat = smrEyeBrow.sharedMaterial;
                break;
            case ColorTargetType.EyeLash:
                mat = smrEyeLash.sharedMaterial;
                break;
            case ColorTargetType.EyeFold:
                mat = smrEyeFold.sharedMaterial;
                break;
            case ColorTargetType.EyeHl:
                mat = smrEyeHl.sharedMaterial;
                break;
            case ColorTargetType.EyeHl2:
                mat = smrEyeHl2.sharedMaterial;
                break;
            case ColorTargetType.EyePupil:
                mat = smrEyePupil.sharedMaterial;
                break;
            default:
                throw new Exception();
        }
        return mat;
    }
    string GenerateTargetsColorCode()
    {
        MatCodeGenerator mcg = new MatCodeGenerator(this);
        var values = Enum.GetValues(typeof(ColorTargetType));
        string str = colorsHead;
        for (int i = 1; i < values.Length; i++)
        {
            var mat = GetTargetMaterial((ColorTargetType)values.GetValue(i));
            str += mcg.GetMaterialCode(mat) + '_';
        }
        str = str.Substring(0, str.Length - 1);
        return str;
    }
    void ReadTargetMatColorCode(string v)
    {
        MatCodeGenerator mcg = new MatCodeGenerator(this);
        var data = v.Split('_');
        var values = Enum.GetValues(typeof(ColorTargetType));
        for (int i = 0; i < data.Length; i++)
        {
            mcg.SetCodeToMat(GetTargetMaterial((ColorTargetType)values.GetValue(i + 1)), data[i]);
        }
    }
    void SelectMirror()
    {
        if (paintModeToggle.isOn || windToggle.isOn) return;
        var m = new List<HairUnit>();
        foreach (var unit in scaler.unitsSelected)
        {
            if (!scaler.unitsSelected.Contains(unit.mirror) && !m.Contains(unit.mirror))
            {
                m.Add(unit.mirror);
            }
        }
        scaler.unitsSelected.AddRange(m);
        emitter.RefreshCullingObjects();
    }
    private void Update()
    {
        if (LightDirAutoTurnOn)
        {
            LightAutoTurnTimer += Time.deltaTime * LightDirAutoTurnSpeedSlider.value;
            var v = Mathf.Repeat(lightDirHorizonSlider.value + LightAutoTurnTimer, 360);
            OnLightDirHorizonChanged(v);
        }

        var alt = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
        var shift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
        var ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);

        // always
        if (Input.GetKeyDown(KeyCode.Q))
        {
            painter.facePanelToggle.isOn = !painter.facePanelToggle.isOn; return;
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            painter.paintPanelToggle.isOn = !painter.paintPanelToggle.isOn; return;
        }
        else if (Input.GetKeyDown(KeyCode.H))
        {
            outlineDisplayToggle.isOn = !outlineDisplayToggle.isOn; return;
        }
        if (Input.GetKeyDown(KeyCode.R) && !ctrl && !shift && !alt)
        {
            mirrorControlToggle.isOn = !mirrorControlToggle.isOn;
            return;
        }
        //
        if (windToggle.isOn) // wind mode
        {
            if (Input.GetKeyDown(KeyCode.W))
            {
                windToggle.isOn = !windToggle.isOn;
            }
            return; // disable other key when windmode
        }
        if (!manualGizmos.gameObject.activeInHierarchy) // !manual mode
        {
            if (!windToggle.isOn) // && !wind
            {
                if (Input.GetKeyDown(KeyCode.X))
                {
                    emitter.DeleteUnit();
                }
                else if (Input.GetKeyDown(KeyCode.N))
                {
                    emitter.NewUnit();
                }
                else if (Input.GetKeyDown(KeyCode.A))//selection
                {
                    if (hairSelector.value == 0)
                    {
                        hairSelector.value = hairSelector.maxValue;
                    }
                    else
                    {
                        hairSelector.value = 0;
                    }
                }
                else if (Input.GetKeyDown(KeyCode.W))
                {
                    windToggle.isOn = true;
                    return;
                }
#if UNITY_EDITOR
                else if (shift && Input.GetKeyDown(KeyCode.F))//Editor环境中因为不能Ctrl，以此作为替代。
                {
                    emitter.CreateMirrorConnect();
                }
#endif
                else if (Input.GetKeyDown(KeyCode.R))
                {
                    if (ctrl)
                    {
                        emitter.CreateMirrorConnect();
                    }
                    else if (shift)
                    {
                        SelectMirror();
                    }
                    else if (alt)
                    {
                        emitter.ReleaseMirrorConnect();
                    }
                    return;
                }
                else if (Input.GetKeyDown(KeyCode.D))
                {
                    if (shift)
                    {
                        emitter.DuplicateUnits();
                    }
                }
            }
        }
        // !windmode
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            manualSectionPosToggle.isOn = !manualSectionPosToggle.isOn;
        }
        else if (Input.GetKeyDown(KeyCode.O))
        {
            proportionalEditToggle.isOn = !proportionalEditToggle.isOn;
        }
        else if (Input.GetKeyDown(KeyCode.S))
        {
            manualKeepChildPosToggle.isOn = !manualKeepChildPosToggle.isOn;
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            manualKeepParentRotToggle.isOn = !manualKeepParentRotToggle.isOn;
        }
    }
    void OnPaintModeChanged(bool v)
    {
        if (v) hairSelector.value = 0;
        foreach (var unit in emitter.hairUnits)
        {
            //unit.smr.enabled = !v;
            unit.smr.GetComponent<Collider>().enabled = !v;
        }
        painter.smr.GetComponent<Collider>().enabled = v;
        painter.isOn = v;
    }
    void OnMouseSelectModeOptionOneSelected(bool v)
    {
        emitter.handMode = v ? HairUnitEmitter.one : HairUnitEmitter.two;
        mouseSelectModeOptionTwo.isOn = !v;
    }
    void OnMouseSelectModeOptionTwoSelected(bool v)
    {
        emitter.handMode = !v ? HairUnitEmitter.one : HairUnitEmitter.two;
        mouseSelectModeOptionOne.isOn = !v;
    }
    void Awake()
    {
        //smrEye.sharedMaterials = smrEye.materials;
        //smrEyeBrow.sharedMaterials = smrEyeBrow.materials;
        //smrEyeFold.sharedMaterials = smrEyeFold.materials;
        //smrEyeHl.sharedMaterials = smrEyeHl.materials;
        //smrEyeHl2.sharedMaterials = smrEyeHl2.materials;
        //smrEyeLash.sharedMaterials = smrEyeLash.materials;
        //smrEyePupil.sharedMaterials = smrEyePupil.materials;
        //smrEyeWhite.sharedMaterials = smrEyeWhite.materials;

        scaler = GetComponent<HairUnitScaler>();
        face = FindObjectOfType<FaceRigControl>();
        hairSegmentSlider.Init(origin, min, max, OnSegmentChanged);
        ignoreValueChanges = true;

        lightDirHorizonSlider.Init(lightDirHorizonMOM, OnLightDirHorizonChanged);
        lightDirVerticalSlider.Init(lightDirVerticalMOM, OnLightDirVerticalChange);
        LightDirAutoTurnToggle.onValueChanged.AddListener(OnLightDirAutoTurnToggleChanged);
        LightDirAutoTurnSpeedSlider.Init(LightDirAutoTurnSpeedMOM, null);
        hairStencilOutAplhaSlider.Init(hairStencilOutAplhaMOM, OnHairStencilOutAplhaChanged);

        mouseDragSensitivitySlider.Init(mouseDragSensitivityMOM, OnMouseDragSensitivity);
        mouseSelectModeOptionOne.onValueChanged.AddListener(OnMouseSelectModeOptionOneSelected);
        mouseSelectModeOptionTwo.onValueChanged.AddListener(OnMouseSelectModeOptionTwoSelected);
        mouseSelectModeOptionTwo.isOn = true;

        proportionalEditToggle.onValueChanged.AddListener(OnProportionalEditToggle);
        proportionalEditOn = proportionalEditToggle.isOn;
        outlineDisplay = FindObjectOfType<RTOverlay>();
        outlineDisplayToggle.isOn = outlineDisplay.enabled;
        outlineDisplayToggle.onValueChanged.AddListener(OnOutlineDisplayToggle);

        FindObjectOfType<CameraCallBack>().onPostRender = OnPostRenderCallBack;
        proportionalEditRangeSlider.Init(proportionalEditRangeMOM, OnProportionalEditRangeChange);

        paintModeToggle.onValueChanged.AddListener(OnPaintModeChanged);

        eyeBrowBoneToggle.isOn = smrEyeBrow.enabled;
        eyeBrowBoneToggle.onValueChanged.AddListener(OnEyeBrowBoneToggle);
        eyeFoldToggle.isOn = smrEyeFold.enabled;
        eyeFoldToggle.onValueChanged.AddListener(OnEyeFoldToggle);
        eyeLashToggle.isOn = smrEyeLash.enabled;
        eyeLashToggle.onValueChanged.AddListener(OnEyeLashToggle);
        eyeHlToggle.isOn = smrEyeHl.enabled;
        eyeHlToggle.onValueChanged.AddListener(OnEyeHlToggle);
        eyeHl2Toggle.isOn = smrEyeHl2.enabled;
        eyeHl2Toggle.onValueChanged.AddListener(OnEyeHl2Toggle);

        manualDragSensitivitySlider.Init(manualDragSensitivityMOM, OnManualDragSensitivity);
        //manualGizmos.axis.gameObject.SetActive(false);
        manualKeepParentRotToggle.onValueChanged.AddListener(OnManualKeepParentRotToggle);
        manualKeepLookAtRotOn = manualKeepParentRotToggle.isOn;
        manualKeepChildPosToggle.onValueChanged.AddListener(OnManualKeepChildPosToggle);
        manualKeepChildPosOn = manualKeepChildPosToggle.isOn;
        manualSectionPosToggle.onValueChanged.AddListener(OnManualSectionPosToggle);
        manualSectionPosOn = manualSectionPosToggle.isOn;
        faceCodeSaveButton.onClick.AddListener(OnSaveFaceCode);
        faceCodeOpenButton.onClick.AddListener(OnOpenFaceCode);
        matCapTileXSlider.Init(matCapTileXMOM, OnMatCapTileXChanged);
        matCapTileYSlider.Init(matCapTileYMOM, OnMatCapTileYChanged);
        //matCapOffsetXSlider.Init(matCapOffsetXMOM, OnMatCapOffsetXChanged);
        matCapOffsetYSlider.Init(matCapOffsetYMOM, OnMatCapOffsetYChanged);
        mirrorControlToggle.onValueChanged.AddListener(ToggleMirrorControl);
        foreach (var block in blocks)
        {
            block.SetActive(!editable);
        }

        hairSelector.onValueChanged = OnHairSelectionChanged;
        hairEndSelector.onValueChanged = OnHairEndTypeChanged;

        colorTargetMOM.z = Enum.GetValues(typeof(ColorTargetType)).Length - 1;
        colorTargetSelector.Init(colorTargetMOM, OnColorTargetSelectChanged);

        rangeHlSlider.Init(rangeOrigin, OnRangeHlChanged);
        rimSlider.Init(rimOrigin, OnRimChanged);
        rimToggle.onValueChanged.AddListener(OnRimToggleChange);
        matCapSlider.Init(matCapOrigin, OnMatCapChanged);
        lightSlider.Init(lightOrigin, OnLightColorChanged);
        darkSlider.Init(darkOrigin, OnDarkColorChanged);
        dark2Slider.Init(dark2Origin, OnDark2ColorChanged);
        rangeHlPowerSlider.Init(rangeHlPowerMOM, OnRangeHlPowerChanged);
        rimPowerSlider.Init(rimPowerMOM, OnRimPowerChanged);
        darkStepSlider.Init(darkStepMOM, OnDarkStepChanged);
        dark2StepSlider.Init(dark2StepMOM, OnDark2StepChanged);
        darkFeatherSlider.Init(darkFeatherMOM, OnDarkFeatherChanged);
        dark2FeatherSlider.Init(dark2FeatherMOM, OnDark2FeatherChanged);
        ignoreValueChanges = false;
    }
    private void OnManualKeepParentRotToggle(bool on)
    {
        manualKeepLookAtRotOn = on;
    }
    private void OnManualKeepChildPosToggle(bool on)
    {
        manualKeepChildPosOn = on;
    }
    private void OnManualSectionPosToggle(bool on)
    {
        manualSectionPosOn = on;
        if (ignoreValueChanges) return;
        if (!on)
        {
            manualGizmos.gameObject.SetActive(false);
            // 更新节点位置；
            foreach (var unit in emitter.hairUnits)
            {
                unit.UpdateColliderAndSectionTrans();
            }
        }
        else
        {
            if (painter.facePanelToggle.isOn) painter.facePanelToggle.isOn = false;
            if (scaler.unitsSelected.Count == 0)
            {
                var o = ignoreValueChanges;
                ignoreValueChanges = true;
                manualSectionPosToggle.isOn = false;
                ignoreValueChanges = o;
            }
            else
            {
                ShowManualSectionPosGizmos();
            }
        }
    }
    public string GetTargetName(ColorTargetType type)
    {
        switch (type)
        {
            case ColorTargetType.Hair:
                return "头发";
            case ColorTargetType.Skin:
                return "皮肤";
            case ColorTargetType.EyeWhite:
                return "眼白";
            case ColorTargetType.Eye:
                return "眼睛";
            case ColorTargetType.EyeBrow:
                return "眉毛";
            case ColorTargetType.EyeLash:
                return "睫毛";
            case ColorTargetType.EyeFold:
                return "折痕";
            case ColorTargetType.EyeHl:
                return "高光";
            case ColorTargetType.EyeHl2:
                return "高光2";
            case ColorTargetType.EyePupil:
                return "瞳孔";
            default:
                throw new Exception();
        }
    }
    bool OnTargetColorChanged()
    {
        if (colorTargetType != ColorTargetType.Hair)
        {
            ApplyUIColorToTarget();
            return true;
        }
        else return false;
    }
    private void OnRangeHlChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = rangeHlSlider.color;
        SetColor(rangeHlName, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.rangeHlColor = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.rangeHlColor = color;
            }
        }
    }
    private void OnRimChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = rimSlider.color;
        SetColor(rimName, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.rimColor = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.rimColor = color;
            }
        }
    }
    private void OnMatCapChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = matCapSlider.color;
        SetColor(matCapName, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.matCapColor = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.matCapColor = color;
            }
        }
    }
    void OnMatCapOffsetXChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var osX = matCapOffsetXSlider.value;
        SetTextureOffset(matCapTexName, new Vector2(osX, matCapOffsetYSlider.value));
        foreach (var unit in scaler.unitsSelected)
        {
            unit.matCapOffset.x = osX;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.matCapOffset.x = osX;
            }
        }
    }
    void OnMatCapOffsetYChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var osY = matCapOffsetYSlider.value;
        SetTextureOffset(matCapTexName, new Vector2(0, osY));
        foreach (var unit in scaler.unitsSelected)
        {
            unit.matCapOffset.y = osY;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.matCapOffset.y = osY;
            }
        }
    }
    void OnMatCapTileXChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var tileX = matCapTileXSlider.value;
        SetTextureScale(matCapTexName, new Vector2(tileX, matCapTileYSlider.value));
        foreach (var unit in scaler.unitsSelected)
        {
            unit.matCapScale.x = tileX;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.matCapScale.x = tileX;
            }
        }
    }
    void OnMatCapTileYChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var tileY = matCapTileYSlider.value;
        SetTextureScale(matCapTexName, new Vector2(matCapTileXSlider.value, tileY));
        foreach (var unit in scaler.unitsSelected)
        {
            unit.matCapScale.y = tileY;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.matCapScale.y = tileY;
            }
        }
    }
    void ToggleMirrorControl(bool value)
    {
        mirrorControl = value;
    }
    private void OnColorTargetSelectChanged(float v)
    {
        colorTargetType = (ColorTargetType)v;
        colorTargetSelector.text.text = GetTargetName(colorTargetType);
        if (colorTargetType != ColorTargetType.Hair)
        {
            ignoreValueChanges = true;
            GetTargetValueToUI();
            ignoreValueChanges = false;
        }
    }
    #region Color
    private void OnLightColorChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = lightSlider.color;
        SetColor(lightName, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.lightColor = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.lightColor = color;
            }
        }
    }
    private void OnRimPowerChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var step = rimPowerSlider.value;
        SetFloat(rimPowerName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.rimPower = step;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.rimPower = step;
            }
        }
    }
    private void OnRangeHlPowerChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var step = rangeHlPowerSlider.value;
        SetFloat(rangeHlPowerName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.rangeHlPower = step;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.rangeHlPower = step;
            }
        }
    }
    void OnDarkStepChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var step = darkStepSlider.value;
        SetFloat(darkStepName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.darkStep = step;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.darkStep = step;
            }
        }
    }
    void OnDark2StepChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var step = dark2StepSlider.value;
        SetFloat(dark2StepName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.dark2Step = step;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.dark2Step = step;
            }
        }
    }
    void OnDarkFeatherChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var feather = darkFeatherSlider.value;
        SetFloat(darkFeatherName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.darkFeather = feather;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.darkFeather = feather;
            }
        }
    }
    void OnDark2FeatherChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var feather = dark2FeatherSlider.value;
        SetFloat(dark2FeatherName, v);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.dark2Feather = feather;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.dark2Feather = feather;
            }
        }
    }
    private void OnDarkColorChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = darkSlider.color;
        SetColor(darkName, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.darkColor = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.darkColor = color;
            }
        }
    }
    private void OnDark2ColorChanged(float v)
    {
        if (ignoreValueChanges) return;
        if (OnTargetColorChanged()) return;
        var color = dark2Slider.color;
        SetColor(dark2Name, color);
        foreach (var unit in scaler.unitsSelected)
        {
            unit.dark2Color = color;
            if (unit.mirror != null && mirrorControl)
            {
                unit.mirror.dark2Color = color;
            }
        }
    }
    #endregion
    #region Set
    void SetTextureScale(string name, Vector2 scale)
    {
        foreach (var unit in scaler.unitsSelected)
        {
            var mat = unit.smr.material;
            mat.SetTextureScale(name, scale);
            unit.smr.materials = new Material[] { mat, mat };
            if (unit.mirror != null && mirrorControl)
            {
                mat = unit.mirror.smr.material;
                mat.SetTextureScale(name, scale);
                unit.mirror.smr.materials = new Material[] { mat, mat };
            }
        }
    }
    void SetTextureOffset(string name, Vector2 offset)
    {
        foreach (var unit in scaler.unitsSelected)
        {
            var mat = unit.smr.material;
            mat.SetTextureOffset(name, offset);
            unit.smr.materials = new Material[] { mat, mat };
            if (unit.mirror != null && mirrorControl)
            {
                mat = unit.mirror.smr.material;
                mat.SetTextureOffset(name, offset);
                unit.mirror.smr.materials = new Material[] { mat, mat };
            }
        }
    }
    void SetColor(string name, Color color)
    {
        foreach (var unit in scaler.unitsSelected)
        {
            var mat = unit.smr.material;
            mat.SetColor(name, color);
            unit.smr.materials = new Material[] { mat, mat };
            if (unit.mirror != null && mirrorControl)
            {
                mat = unit.mirror.smr.material;
                mat.SetColor(name, color);
                unit.mirror.smr.materials = new Material[] { mat, mat };
            }
        }
    }
    void SetFloat(string name, float value)
    {
        foreach (var unit in scaler.unitsSelected)
        {
            var mat = unit.smr.material;
            mat.SetFloat(name, value);
            unit.smr.materials = new Material[] { mat, mat };
            if (unit.mirror != null && mirrorControl)
            {
                mat = unit.mirror.smr.material;
                mat.SetFloat(name, value);
                unit.mirror.smr.materials = new Material[] { mat, mat };
            }
        }
    }
    #endregion
    void OnHairEndTypeChanged(float value)
    {
        if (ignoreValueChanges) return;
        var i = (int)value;
        var mesh = emitter.endTypeMeshs[i];
        foreach (var unit in scaler.unitsSelected)
        {
            unit.endType = i;
            hairEndSelector.text.text = GetHairUnitEndTypeName(unit.endType);
            unit.smr.sharedMesh = mesh;
            scaler.ApplyUnitValue(unit);
            var mirror = unit.mirror;
            if (mirrorControl && mirror != null)
            {
                mirror.endType = i;
                mirror.smr.sharedMesh = mesh;
                scaler.ApplyUnitValue(mirror);
            }
        }
    }
    private string GetHairUnitEndTypeName(int endType)
    {
        HairUnitEndType hairUnitEndType = (HairUnitEndType)endType;
        switch (hairUnitEndType)
        {
            case HairUnitEndType.Sharp:
                return "尖";
            case HairUnitEndType.Flat:
                return "平";
            default:
                throw new Exception("");
        }
    }
    public void OnHairSelectionChanged(float value)
    {
        if (ignoreValueChanges) return;
        colorTargetSelector.value = (float)ColorTargetType.Hair;
        int index = (int)value;
        if (index == 0) // 0则取消选择
        {
            scaler.unitsSelected.Clear(); // clear
        }
        else if (index == (int)hairSelector.maxValue) // max则全选
        {
            scaler.unitsSelected = new List<HairUnit>(emitter.hairUnits);            
            index--;
        }
        else
        {
            scaler.unitsSelected = new List<HairUnit>();
            scaler.unitsSelected.Add(emitter.hairUnits[index - 1]);
        }
        if (scaler.unitsSelected.Count > 0 && index > 0)
        {
            GetUnitValueToUI(emitter.hairUnits[index - 1]);
            if (manualSectionPosOn)
            {
                ShowManualSectionPosGizmos();
            }
        }
        emitter.RefreshCullingObjects();
    }
    public void ShowManualSectionPosGizmos()
    {
        manualGizmos.Init();
        if (scaler.unitsSelected.Count == 0) return;
        var unit = scaler.unitsSelected[0];
        var sections = unit.GetComponentsInChildren<UnityChan.SpringBone>();
        manualGizmos.sections.Clear();
        for (int i = 0; i < sections.Length; i++)
        {
            manualGizmos.sections.Add(sections[i].transform);
            manualGizmos.balls[i].position = sections[i].transform.position;
            manualGizmos.balls[i].rotation = sections[i].transform.rotation;
        }
        manualGizmos.gameObject.SetActive(true);
    }
    // just use when emitt new hair
    public void CallUIOnChanged()
    {
        rangeHlSlider.onValueChanged(0);
        rangeHlPowerSlider.onValueChanged(rangeHlPowerSlider.value);
        rimSlider.onValueChanged(0);
        rimPowerSlider.onValueChanged(rimPowerSlider.value);
        rimToggle.onValueChanged.Invoke(rimToggle.isOn);
        matCapSlider.onValueChanged(0);
        lightSlider.onValueChanged(0);
        darkSlider.onValueChanged(0);
        dark2Slider.onValueChanged(0);
        darkStepSlider.onValueChanged(darkStepSlider.value);
        dark2StepSlider.onValueChanged(dark2StepSlider.value);
        darkFeatherSlider.onValueChanged(darkFeatherSlider.value);
        dark2FeatherSlider.onValueChanged(dark2FeatherSlider.value);

        matCapTileXSlider.onValueChanged(matCapTileXSlider.value);
        matCapTileYSlider.onValueChanged(matCapTileYSlider.value);
        //matCapOffsetXSlider.onValueChanged(matCapOffsetXSlider.value);
        matCapOffsetYSlider.onValueChanged(matCapOffsetYSlider.value);
    }
    internal void ApplyUnitColorToMaterial(HairUnit unit)
    {
        var mat = unit.smr.sharedMaterial;
        mat.SetColor(rangeHlName, unit.rangeHlColor);
        mat.SetFloat(rangeHlPowerName, unit.rangeHlPower);
        mat.SetColor(rimName, unit.rimColor);
        mat.SetFloat(rimPowerName, unit.rimPower);
        mat.SetFloat(rimToggleName, unit.rimOn ? 1 : 0);
        mat.SetColor(matCapName, unit.matCapColor);
        mat.SetColor(lightName, unit.lightColor);
        mat.SetFloat(darkStepName, unit.darkStep);
        mat.SetFloat(darkFeatherName, unit.darkFeather);
        mat.SetColor(darkName, unit.darkColor);
        mat.SetFloat(dark2StepName, unit.dark2Step);
        mat.SetFloat(dark2FeatherName, unit.dark2Feather);
        mat.SetColor(dark2Name, unit.dark2Color);
        mat.SetTextureScale(matCapTexName, unit.matCapScale);
        mat.SetTextureOffset(matCapTexName, unit.matCapOffset);
    }
    internal void ApplyUnitValues(HairUnit unit)
    {
        manualGizmos.UpdateUnitScale(unit);
        scaler.OnLengthChanged(unit, scaler.lengthSlider.value);
    }
    public void ApplyUIColorToMaterial(Material mat)
    {
        mat.SetColor(rangeHlName, rangeHlSlider.color);
        mat.SetFloat(rangeHlPowerName, rangeHlPowerSlider.value);
        mat.SetColor(rimName, rimSlider.color);
        mat.SetFloat(rimPowerName, rimPowerSlider.value);
        mat.SetFloat(rimToggleName, rimToggle.isOn ? 1 : 0);
        mat.SetColor(matCapName, matCapSlider.color);
        mat.SetColor(lightName, lightSlider.color);
        mat.SetFloat(darkStepName, darkStepSlider.value);
        mat.SetFloat(darkFeatherName, darkFeatherSlider.value);
        mat.SetColor(darkName, darkSlider.color);
        mat.SetFloat(dark2StepName, dark2StepSlider.value);
        mat.SetFloat(dark2FeatherName, dark2FeatherSlider.value);
        mat.SetColor(dark2Name, dark2Slider.color);
        mat.SetTextureScale(matCapTexName, new Vector2(matCapTileXSlider.value, matCapTileYSlider.value));
        mat.SetTextureOffset(matCapTexName, new Vector2(0, matCapOffsetYSlider.value));
    }
    internal void ApplyUIColorToTarget()
    {
        Material mat = GetTargetMaterial(colorTargetType);
        ApplyUIColorToMaterial(mat);
    }
    public void ApplyUIValueToHair(HairUnit unit, bool firstTime = true)
    {
        unit.rangeHlColor = rangeHlSlider.color;
        unit.rangeHlPower = rangeHlPowerSlider.value;
        unit.rimColor = rimSlider.color;
        unit.rimPower = rimPowerSlider.value;
        unit.rimOn = rimToggle.isOn;
        unit.matCapColor = matCapSlider.color;
        unit.lightColor = lightSlider.color;
        unit.darkColor = darkSlider.color;
        unit.dark2Color = dark2Slider.color;
        unit.darkStep = darkStepSlider.value;
        unit.dark2Step = dark2StepSlider.value;
        unit.darkFeather = darkFeatherSlider.value;
        unit.dark2Feather = dark2FeatherSlider.value;

        unit.matCapScale = new Vector2(matCapTileXSlider.value, matCapTileYSlider.value);
        unit.matCapOffset = new Vector2(0, matCapOffsetYSlider.value);

        scaler.unitsSelected.Clear();
        scaler.unitsSelected.Add(unit);

        unit.endType = (int)hairEndSelector.slider.value;
        for (int i = 0; i < unit.sectionWidth.Length; i++)
        {
            unit.sectionWidth[i] = scaler.widthSlider.value;
        }
        for (int i = 0; i < unit.sectionThickness.Length; i++)
        {
            unit.sectionThickness[i] = scaler.thicknessSlider.value;
        }
        manualGizmos.UpdateUnitScale(unit);
        scaler.OnLengthChanged(unit, scaler.lengthSlider.value);
        ApplyUnitColorToMaterial(unit);
    }
    internal void ToggleEditable()
    {
        editable = !editable;

        manualSectionPosToggle.isOn = false;

        foreach (var block in blocks)
        {
            block.SetActive(!editable);
        }

        lightSlider.editable = editable;
        darkSlider.editable = editable;
        dark2Slider.editable = editable;

        darkStepSlider.editable = editable;
        dark2StepSlider.editable = editable;

        darkFeatherSlider.editable = editable;
        dark2FeatherSlider.editable = editable;

        hairEndSelector.editable = editable;
        hairSelector.editable = editable;
        scaler.thicknessSlider.editable = editable;
        scaler.widthSlider.editable = editable;
        scaler.lengthSlider.editable = editable;
    }
    internal void SetMaterialValuesToUI(Material mat)
    {
        rangeHlSlider.color = mat.GetColor(rangeHlName);
        rangeHlPowerSlider.value = mat.GetFloat(rangeHlPowerName);
        rimSlider.color = mat.GetColor(rimName);
        rimPowerSlider.value = mat.GetFloat(rimPowerName);
        rimToggle.isOn = mat.GetFloat(rimToggleName) > 0 ? true : false;
        matCapSlider.color = mat.GetColor(matCapName);
        lightSlider.color = mat.GetColor(lightName);
        darkSlider.color = mat.GetColor(darkName);
        dark2Slider.color = mat.GetColor(dark2Name);

        darkStepSlider.value = mat.GetFloat(darkStepName);
        dark2StepSlider.value = mat.GetFloat(dark2StepName);

        darkFeatherSlider.value = mat.GetFloat(darkFeatherName);
        dark2FeatherSlider.value = mat.GetFloat(dark2FeatherName);

        matCapTileXSlider.value = mat.GetTextureScale(matCapTexName).x;
        matCapTileYSlider.value = mat.GetTextureScale(matCapTexName).y;
        //matCapOffsetXSlider.value = unit.matCapOffset.x;
        matCapOffsetYSlider.value = mat.GetTextureOffset(matCapTexName).y;
    }
    public void GetTargetValueToUI()
    {
        var mat = GetTargetMaterial(colorTargetType);
        SetMaterialValuesToUI(mat);
    }
    public void GetUnitValueToUI(HairUnit unit)
    {
        var o = ignoreValueChanges;
        ignoreValueChanges = true;
        rangeHlSlider.color = unit.rangeHlColor;
        rangeHlPowerSlider.value = unit.rangeHlPower;
        rimSlider.color = unit.rimColor;
        rimPowerSlider.value = unit.rimPower;
        rimToggle.isOn = unit.rimOn;
        matCapSlider.color = unit.matCapColor;
        lightSlider.color = unit.lightColor;
        darkSlider.color = unit.darkColor;
        dark2Slider.color = unit.dark2Color;
        darkStepSlider.value = unit.darkStep;
        dark2StepSlider.value = unit.dark2Step;
        darkFeatherSlider.value = unit.darkFeather;
        dark2FeatherSlider.value = unit.dark2Feather;
        matCapTileXSlider.value = unit.matCapScale.x;
        matCapTileYSlider.value = unit.matCapScale.y;
        //matCapOffsetXSlider.value = unit.matCapOffset.x;
        matCapOffsetYSlider.value = unit.matCapOffset.y;

        hairEndSelector.value = unit.endType;
        hairEndSelector.text.text = GetHairUnitEndTypeName(unit.endType);
        scaler.thicknessSlider.slider.value = unit.sectionThickness[0];
        scaler.widthSlider.slider.value = unit.sectionWidth[0];
        scaler.lengthSlider.slider.value = Vector3.Distance(unit.sectionPosition[0], unit.sectionPosition[1]);
        ignoreValueChanges = o;
    }
    void OnSegmentChanged(float value)
    {
        if (ignoreValueChanges) return;
        var segment = Mathf.FloorToInt(value);
        var odd = segment * 0.5f;
        if ((int)odd != odd)
        {
            segment++;
        }
        bool originIgnoreValueChanges = ignoreValueChanges;
        ignoreValueChanges = true;
        hairSegmentSlider.value = segment;
        ignoreValueChanges = originIgnoreValueChanges;
        emitter.segment = segment;
    }
}
